﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using NUnit.Framework;
using System.Collections;
using System.Reflection;
using System.Configuration;
using AutoTestingFramework.Core.Configurations;
using AutoTestingFramework.Utilities;

namespace AutoTestingFramework.Core.TestData
{
    public abstract class TestDataBase
    {
        protected static TestDataConfigurationSection _testDataConfig =
                      (TestDataConfigurationSection)ConfigurationManager.GetSection("TestDataSource");

        private string _testCaseDataBasePath = _testDataConfig.TestDataBase.TestCaseDataBasePath;
        /// <summary>
        /// A relative path for test data.
        /// It should be read from config
        /// </summary>
        public string TestCaseDataBasePath
        {
            get
            {
                if (string.IsNullOrWhiteSpace(_testCaseDataBasePath))
                    throw new Exception("Config file 'TestCaseDataBasePath' section property is not set yet.");
                return _testCaseDataBasePath;
            }
            set
            {
                if (!value.EndsWith(@"/"))
                    value += @"/";
                _testCaseDataBasePath = value;
            }
        }

        /// <summary>
        /// A delegate function can read test data from data source, 
        /// and this function with a parameter which indicates the data source physical path.
        /// </summary>
        public Func<string, DataTable> ReadTestData { get; set; }




    }

    public abstract class TestDataBase<T> : TestDataBase where T : TestDataBase
    {   

        private string _testDataFileName = _testDataConfig.
                                           TestCaseDataCollection[typeof(T).Name].
                                           TestCaseDataFileName;
        /// <summary>
        /// A  porperty which stored test data file name,but it's not contain file extension.
        /// <remarks>warring:test data file's name should be same with specific test data class name.</remarks>
        /// </summary>
        public string TestDataFileName
        {
            get
            {
                if (string.IsNullOrWhiteSpace(_testDataFileName))
                    throw new Exception("Config file 'TestCaseDataFileName' section property is not set yet.");
                return _testDataFileName;
            }
            set { _testDataFileName = value; }
        }

        private string _testDataFileColumns = _testDataConfig.
                                              TestCaseDataCollection[typeof(T).Name].
                                              ColumnsNameListWithComma;
        /// <summary>
        /// A porperty contains which columns should be read from excel,and each column split by comma.
        /// </summary>
        public List<string> TestDataFileColumnsList
        {
            get
            {
                if (string.IsNullOrWhiteSpace(_testDataFileColumns))
                    throw new Exception("Config file 'ColumnsNameListWithComma' section property is not set yet.");
                return _testDataFileColumns.Split(',').ToList();
            }
        }
        /// <summary>
        /// This constructor initializes the function which can read test data .
        /// </summary>
        public TestDataBase()
        {
            if (ReadTestData == null)
            {
                ReadTestData = (path) => (ExcelHelper2.ReadExcelData(path));
            }

        }
        /// <summary>
        /// A virtual function can read each column into test case data.
        /// </summary>
        /// <returns>Test cases list</returns>
        public virtual IEnumerable<TestCaseData> TestDataTestCases()
        {
            List<TestCaseData> testCaseDataList = new List<TestCaseData>();

            var data = ReadTestData(TestCaseDataBasePath + TestDataFileName);

            foreach (DataRow item in data.Rows)
            {
                //which columns should be read, 
                //and how to add those column values into TestCaseData object? 
                //how to read each column dynamically ? -solved by cooper

                List<object> list = new List<object>();
                foreach (var col in TestDataFileColumnsList)
                {
                    list.Add(item[col].ToString());
                }
                object[] objs = list.ToArray() ;

                testCaseDataList.Add(new TestCaseData(objs));
               
            }

            return testCaseDataList;
        }



    }
}
